package com.inspur.edp.formserver.vmmanager.service;

import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.collection.CommonDtmCollection;
import com.inspur.edp.cef.designtime.api.exceptions.CefException;
import com.inspur.edp.cef.designtime.api.operation.CommonDetermination;
import com.inspur.edp.das.commonmodel.IGspCommonElement;
import com.inspur.edp.das.commonmodel.IGspCommonObject;
import com.inspur.edp.das.commonmodel.entity.GspCommonElement;
import com.inspur.edp.formserver.viewmodel.GspViewModel;
import com.inspur.edp.formserver.viewmodel.GspViewModelElement;
import com.inspur.edp.formserver.viewmodel.GspViewObject;
import com.inspur.edp.formserver.viewmodel.action.MappedCdpAction;
import com.inspur.edp.formserver.viewmodel.action.MappedCdpActionBase;
import com.inspur.edp.formserver.viewmodel.action.ViewModelAction;
import com.inspur.edp.formserver.viewmodel.action.ViewModelActionType;
import com.inspur.edp.formserver.viewmodel.collection.VMActionCollection;
import com.inspur.edp.formserver.viewmodel.common.ValueHelpConfig;
import com.inspur.edp.formserver.viewmodel.common.ViewModelErrorCodes;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.entity.MetadataReference;
import com.inspur.edp.lcm.metadata.api.service.RefCommonService;
import com.inspur.edp.lcm.metadata.spi.IMetadataReferenceManager;
import io.iec.edp.caf.commons.exception.CAFRuntimeException;
import io.iec.edp.caf.commons.exception.ExceptionLevel;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class MetadataReferenceService implements IMetadataReferenceManager {

  private HashMap<String, String> map = new HashMap<String, String>();
  private String errorCode = "MetadataReferenceService";
  //TODO 临时添加
  private String errorToken = "#GSPBefError# ";
  private void buildMetadataReference(GspMetadata metadata) {
    if (metadata.getRefs() == null) {
      metadata.setRefs(new ArrayList<MetadataReference>());
    }
    map.clear();
    RefCommonService refService = SpringBeanUtils.getBean(RefCommonService.class);
    GspViewModel vm = (GspViewModel) metadata.getContent();
    addAssoVirtualFieldBeReference(vm,metadata,refService);
    addActionReference(vm,metadata,refService);
    // 虚拟vo无依赖
    if (vm.getIsVirtual()) {
      return;
    }

    // ① vm.Mapping
    String beId = vm.getMapping().getTargetMetadataId();
    addMappingBeReference(beId, metadata, refService);

    // ② obj
    dealObjectReference(vm.getMainObject(), metadata, refService);
    //
    addActionReference(vm,metadata,refService);
  }

  private void addActionReference(GspViewModel vm, GspMetadata metadata, RefCommonService refService) {
    dealActions(vm,metadata,refService);
    dealDataExtendInfo(vm,metadata,refService);
    dealVariables(vm,metadata,refService);
    dealHelpConfig(vm,metadata,refService);
  }

  private void dealVariables(GspViewModel vm, GspMetadata metadata, RefCommonService refService) {
    if (vm.getVariables()==null)
      return;
    if(vm.getVariables().getDtmAfterModify()==null ||vm.getVariables().getDtmAfterModify().size()==0)
      return;
    CommonDtmCollection dtmAfterModify = vm.getVariables().getDtmAfterModify();
    for (CommonDetermination commonDetermination : dtmAfterModify) {
      addMappingBeReference(commonDetermination.getComponentId(), metadata, refService);
    }
  }

  private void dealDataExtendInfo(GspViewModel vm, GspMetadata metadata, RefCommonService refService) {
    if (vm.getDataExtendInfo()==null)
      return;
    VMActionCollection beforeCreateActions = vm.getDataExtendInfo().getBeforeCreateActions();
    addDataExtendInfo(beforeCreateActions,vm,metadata,refService);

    VMActionCollection createActions = vm.getDataExtendInfo().getCreateActions();
    addDataExtendInfo(createActions,vm,metadata,refService);

    VMActionCollection afterCreateActions = vm.getDataExtendInfo().getAfterCreateActions();
    addDataExtendInfo(afterCreateActions,vm,metadata,refService);


    VMActionCollection beforeRetrieveActions = vm.getDataExtendInfo().getBeforeRetrieveActions();
    addDataExtendInfo(beforeRetrieveActions,vm,metadata,refService);

    VMActionCollection retrieveActions = vm.getDataExtendInfo().getRetrieveActions();
    addDataExtendInfo(retrieveActions,vm,metadata,refService);

    VMActionCollection afterRetrieveActions = vm.getDataExtendInfo().getAfterRetrieveActions();
    addDataExtendInfo(afterRetrieveActions,vm,metadata,refService);


    VMActionCollection beforeQueryActions = vm.getDataExtendInfo().getBeforeQueryActions();
    addDataExtendInfo(beforeQueryActions,vm,metadata,refService);

    VMActionCollection queryActions = vm.getDataExtendInfo().getQueryActions();
    addDataExtendInfo(queryActions,vm,metadata,refService);

    VMActionCollection afterQueryActions = vm.getDataExtendInfo().getAfterQueryActions();
    addDataExtendInfo(afterQueryActions,vm,metadata,refService);


    VMActionCollection beforeModifyActions = vm.getDataExtendInfo().getBeforeModifyActions();
    addDataExtendInfo(beforeModifyActions,vm,metadata,refService);

    VMActionCollection modifyActions = vm.getDataExtendInfo().getModifyActions();
    addDataExtendInfo(modifyActions,vm,metadata,refService);

    VMActionCollection afterModifyActions = vm.getDataExtendInfo().getAfterModifyActions();
    addDataExtendInfo(afterModifyActions,vm,metadata,refService);


    VMActionCollection beforeDeleteActions = vm.getDataExtendInfo().getBeforeDeleteActions();
    addDataExtendInfo(beforeDeleteActions,vm,metadata,refService);

    VMActionCollection deleteActions = vm.getDataExtendInfo().getDeleteActions();
    addDataExtendInfo(deleteActions,vm,metadata,refService);

    VMActionCollection afterDeleteActions = vm.getDataExtendInfo().getAfterDeleteActions();
    addDataExtendInfo(afterDeleteActions,vm,metadata,refService);


    VMActionCollection beforeMultiDeleteActions = vm.getDataExtendInfo().getBeforeMultiDeleteActions();
    addDataExtendInfo(beforeMultiDeleteActions,vm,metadata,refService);

    VMActionCollection multiDeleteActions = vm.getDataExtendInfo().getMultiDeleteActions();
    addDataExtendInfo(multiDeleteActions,vm,metadata,refService);

    VMActionCollection afterMultiDeleteActions = vm.getDataExtendInfo().getAfterMultiDeleteActions();
    addDataExtendInfo(afterMultiDeleteActions,vm,metadata,refService);


    VMActionCollection dataMappingActions = vm.getDataExtendInfo().getDataMappingActions();
    addDataExtendInfo(dataMappingActions,vm,metadata,refService);

    VMActionCollection dataReversalMappingActions = vm.getDataExtendInfo().getDataReversalMappingActions();
    addDataExtendInfo(dataReversalMappingActions,vm,metadata,refService);


    VMActionCollection changesetReversalMappingActions = vm.getDataExtendInfo().getChangesetReversalMappingActions();
    addDataExtendInfo(changesetReversalMappingActions,vm,metadata,refService);

    VMActionCollection changesetMappingActions = vm.getDataExtendInfo().getChangesetMappingActions();
    addDataExtendInfo(changesetMappingActions,vm,metadata,refService);


    VMActionCollection beforeSaveActions = vm.getDataExtendInfo().getBeforeSaveActions();
    addDataExtendInfo(beforeSaveActions,vm,metadata,refService);

    VMActionCollection saveActions = vm.getDataExtendInfo().getSaveActions();
    addDataExtendInfo(saveActions,vm,metadata,refService);

    VMActionCollection afterSaveActions = vm.getDataExtendInfo().getAfterSaveActions();
    addDataExtendInfo(afterSaveActions,vm,metadata,refService);


  }
  private void addDataExtendInfo(VMActionCollection actions,GspViewModel vm,GspMetadata metadata,RefCommonService refService){
    if (actions==null || actions.size()==0)
      return;
    for (ViewModelAction action : actions) {
      if (action instanceof MappedCdpActionBase)
        addMappingBeReference(((MappedCdpActionBase) action).getComponentEntityId(),metadata,refService);
    }
  }
  private void dealHelpConfig(GspViewModel vm,GspMetadata metadata,RefCommonService refService){
    if (vm.getValueHelpConfigs()==null || vm.getValueHelpConfigs().size()==0)
      return;
    for (ValueHelpConfig valueHelpConfig : vm.getValueHelpConfigs()) {
      addMappingBeReference(valueHelpConfig.getHelperId(),metadata,refService);
    }
  }
  private void dealActions(GspViewModel vm,GspMetadata metadata,RefCommonService refService){
    if (vm.getActions() == null || vm.getActions().getCount() == 0)
      return;
    for (ViewModelAction action : vm.getActions()) {
      if (action.getType() == ViewModelActionType.VMAction) {
        if (action instanceof MappedCdpAction) {
          buildCompReference((MappedCdpAction) action, metadata, refService);
        }else {
            throw new CefException(ViewModelErrorCodes.GSP_BFF_MODEL_0001,errorToken+action.getName()+"类型应为MappedCdpAction. "+errorToken , null, ExceptionLevel.Error,true);
          }
        }
      }
  }
  private void addAssoVirtualFieldBeReference(GspViewModel viewModel, GspMetadata metadata, RefCommonService refService) {
    List<IGspCommonElement> elementList = viewModel.getAllElementList(false);
    for(IGspCommonElement element : elementList) {
      if (!element.getIsVirtual()) {
        continue;
      }
      if (element.getIsUdt()){
        addMappingBeReference(element.getUdtID(),metadata,refService);
      } else if (element.getHasAssociation()  && element.getChildAssociations().size() >= 0) {
        String refBeId = ((GspCommonElement) element).getChildAssociations().get(0).getRefModelID();
        addMappingBeReference(refBeId, metadata, refService);
      }
    }
  }


  private void dealObjectReference(GspViewObject obj, GspMetadata metadata, RefCommonService refService) {
    if (obj.getIsVirtual()) {
      return;
    }
    // ① mapping
    addMappingBeReference(obj.getMapping().getTargetMetadataId(), metadata, refService);
    // ① Elemnet
    if (obj.getContainElements() != null && obj.getContainElements().getCount() > 0) {
      for (IGspCommonField ele : obj.getContainElements()) {
        dealElementReference( (GspViewModelElement)ele, metadata, refService);
      }
    }

    // ② Child
    if (obj.getContainChildObjects() != null && obj.getContainChildObjects().getCount() > 0) {
      for (IGspCommonObject childObj : obj.getContainChildObjects()) {
        dealObjectReference( (GspViewObject)childObj, metadata, refService);
      }
    }
  }

  private void dealElementReference(GspViewModelElement element, GspMetadata metadata, RefCommonService refService) {
    if (element.getIsUdt()){
      addMappingBeReference(element.getUdtID(),metadata,refService);
    } else if (element.getHasAssociation()  && element.getChildAssociations().size() >= 0) {
      String refBeId = ((GspCommonElement) element).getChildAssociations().get(0).getRefModelID();
      addMappingBeReference(refBeId, metadata, refService);
    }
    //① mapping
    if(element.getIsVirtual())
      return;
    addMappingBeReference(element.getMapping().getTargetMetadataId(), metadata, refService);

  }

  public void buildCompReference(MappedCdpAction operation, GspMetadata metadata, RefCommonService refService) {
    addMappingBeReference(operation.getComponentEntityId(), metadata, refService);
  }

  private void addMappingBeReference(String refBeId, GspMetadata metadata, RefCommonService refService) {
    if (refBeId==null ||"".equals(refBeId) || map.containsKey(refBeId)) {
      return;
    }
    map.put(refBeId, refBeId);
    buildReference(refBeId, metadata, refService);
  }

  private void buildReference(String refMetadataId, GspMetadata metadata, RefCommonService refService) {
    if (refMetadataId==null || "".equals(refMetadataId)) {
      return;
    }
    for (MetadataReference metadataReference : metadata.getRefs()) {
      if (refMetadataId.equals(metadataReference.getDependentMetadata().getId())) {
        return;
      }
    }
    GspMetadata refMetaData=refService.getRefMetadata(refMetadataId);
    if(refMetaData==null){
      StringBuilder builder=new StringBuilder();
      GspViewModel viewModel= (GspViewModel) metadata.getContent();
      builder.append(metadata.getHeader().getNameSpace()).append("命名空间下的").append("编号为:").append(viewModel.getCode()).append("名称为:").append(viewModel.getName()).
              append("的VO元数据在构造依赖的元数据关系时，未找到ID值为").append(refMetadataId).append("的元数据,请确认依赖的元数据是否部署到环境中!");
      throw  new CefException(ViewModelErrorCodes.GSP_BFF_MODEL_0001,builder.toString(),null,ExceptionLevel.Error,true);
    }
    MetadataReference metadataReference = new MetadataReference();
    metadataReference.setMetadata(metadata.getHeader());
    metadataReference.setDependentMetadata(refMetaData.getHeader());
    metadata.getRefs().add(metadataReference);
  }

  public List<MetadataReference> getConstraint(GspMetadata metadata) {
    if(metadata.getRefs()!=null){
      metadata.getRefs().clear();
    }
    buildMetadataReference(metadata);
    List<MetadataReference> list = new ArrayList<>();
    if (metadata.getRefs() != null && metadata.getRefs().size() > 0) {
      for (MetadataReference item : metadata.getRefs()) {
        list.add(item);
      }
    }
    return list;
  }
}
